home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Packmags
/
Source, The - Issue 1 (1993)(Epsilon)[WB].zip
/
Source, The - Issue 1 (1993)(Epsilon)[WB].adf
/
TextFiles
/
howtocode2.txt
< prev
Wrap
Text File
|
1992-12-30
|
17KB
|
550 lines
How to write demos that work (Version 2)
========================================
(or How to bash the metal and get away with it)
by Comrade J, Share and Enjoy (retired)
Are you fed up of downloading a new demo, running it and finding
your Amiga power light sitting there flashing at you? Are you
tired of the contents of your chipram flashing through the bitplane
registers in a rather random fashion when you run 'Duffex's
Megademo'?
Do you want demos that actually run? Because I do. I'm fed up
completely with all these rubbish coders who can't do their job
properly...
Now, since those long days and nights bashing away at Share and Enjoy
demos I've been involved in all sorts of Amiga programming, involving
new AGA machines, CD, 16-bit audio and all sorts of other
wonderful things that I can't talk about, both via the OS and at a
hardware level.
Most demos I've seen use similar startup code to that I was using back
in 1988. Hey guys, wake up! The Amiga has changed quite a bit since
then.
So. Here are some tips on what to do and what not to do:
1. RTFM.
========
Read the F**king manuals. All of them. Borrow them off friends or from
your local public library if you have to. Make sure you follow the
hardware rules to the letter. If it says "Leave this bit cleared" then
don't set it!
There is a lot of useful informatiton in the 'boring' OS Rom Kernal
Manuals that you may be suprised to know.
Read the "General Amiga Development Guidelines" in the new (grey)
Hardware Reference Manual and follow them TO THE LETTER.
Don't use self-modifying code. A common bit of code I see is:
... in the setup code
move.l $6c.w,old
... at the end of the interrupt
movem.l (sp)+,a0-a6/d0-d7
dc.w $4ef9 ; jmp instruction
old dc.l 0 ; self modifying!!!!
DONT DO THIS!
This is much better (although it still hits $6c which is not a
good thing - It's much better to use AddIntServer() to call your
interrupts, but more on that next time....)
... in the setup code
move.l $6c.w,old
... at the end of the interrupt
movem.l (sp)+,a0-a6/d0-d7
move.l old,-(sp) ; push old address to stack
rts
... in your data section
old dc.l 0
68020 and above processors with cache enabled often barf at the first
piece of code (the cache still contains the JMP 0 instruction
which isn't then altered), but the second piece works fine on the '040.
2. Proper Copper startup.
=========================
IF you are going to use the copper then this is how you should set it
up. The current workbench view and copper address are stored, the
system frozen, and then the copper enabled. On exit the workbench
view is restored.
This guarantees your demo will run on an AGA (Amiga 1200) machine,
even if set into some weird screenmode before running your code.
Otherwise under AGA, the hardware registers can be in some strange states
before your code runs, beware!
The LoadView(NULL) forces the display to a standard, empty position,
flushing the crap out of the hardware registers: Note. There is
a bug in the V39 OS on Amiga 1200/4000 and the sprite resolution is
*not* reset, you will have to do this manually if you use sprites...
Two WaitTOF() calls are needed after the LoadView to wait for both the
long and short frame copperlists of interlaced displays to finish.
I'm writing this code off the top of my head, if you spot any obvious bugs
email me at the address below, or leave mail to me on Bad Dreams BBS.
include "exec/macros.i"
include "exec/funcdef.i" ; keep code simple and
include "exec/exec_lib.i" ; easy to read - use
include "graphics/gfxbase.i" ; the includes!
include "graphics/gfx_lib.i"
include "misc/easystart.i" ; Allows startup from
; icon
section mycode,code ; need not be in chipram
StartCopper:
move.l 4.w,a6 ; get ExecBase
lea gfxname,a1 ; graphics name
moveq #0,d0 ; any version
jsr _LVOOpenLibrary(a6)
tst.l d0
beq End ; failed to open? Then quit
move.l d0,gfxbase
move.l d0,a6
move.l gb_ActiView(a6),wbview
; store current view address
; gb_ActiView = 32
move.w #0,a1 ; clears full long-word
jsr _LVOLoadView(a6) ; Flush View to nothing
jsr _LVOWaitTOF(a6) ; Wait once
jsr _LVOWaitTOF(a6) ; Wait again.
; Now you can hit the copper!
move.l 4.w,a6
jsr _LVOForbid(a6) ; Suspend multitasking!
move.l mycopper,$dff080 ; bang it straight in.
; (DO NOT F**K WITH GFXBASE!)
*** DO YOUR FUNKY STUFF HERE ***
CloseDown: move.l 4.w,a6
jsr _LVOPermit(a6) ; Enable multitasking
move.l wbview,a1
move.l gfxbase,a6
jsr _LVOLoadView(a6) ; Fix view
move.l gb_copinit(a6),$dff080 ; Kick it into life
; copinit = 36
move.l a6,a1
move.l 4.w,a6
jsr _LVOCloseLibrary(a6) ; EVERYONE FORGETS THIS!!!!
End: rts
section mydata,data_C ; keep data & code seperate!
copperlist dc.w $180,0 ; background black
dc.w $5c07,$fffe ; wait for $5c07,$fffe
dc.w $180,$ff0 ; background yellow
dc.w $ffff,$fffe
dc.w $ffff,$fffe ; Copper end (always do two
; copper end cmds!)
wbview dc.l 0
wbcop dc.l 0
gfxbase dc.l 0
gfxname dc.b "graphics.library",0
3. Your code won't run from an icon.
====================================
You stick an icon for your new demo (not everyone uses the CLI!) and
it either crashes or doesn't give back all the RAM it uses. Why?
Icon startup needs specific code to reply to the workbench message.
With the excellent Hisoft Devpac assember, all you need to do is add
the line
include "misc/easystart.i"
and it magically works!
For those without Devpac, here is the relevent code:
---------------------------------------------------------
* some startup code to make a Workbench execute look like the CLI
* based loosely on RKM Vol 1 page 4-36
* Include this at the front of your program
* after any other includes
* note that this needs exec/exec_lib.i
IFND EXEC_EXEC_I
include "exec/exec.i"
ENDC
IFND LIBRARIES_DOSEXTENS_I
include "libraries/dosextens.i
ENDC
movem.l d0/a0,-(sp) save initial values
clr.l returnMsg
sub.l a1,a1
move.l 4.w,a6
jsr _LVOFindTask(a6) find us
move.l d0,a4
tst.l pr_CLI(a4)
beq.s fromWorkbench
* we were called from the CLI
movem.l (sp)+,d0/a0 restore regs
bra end_startup and run the user prog
* we were called from the Workbench
fromWorkbench
lea pr_MsgPort(a4),a0
move.l 4.w,a6
jsr _LVOWaitPort(A6) wait for a message
lea pr_MsgPort(a4),a0
jsr _LVOGetMsg(A6) then get it
move.l d0,returnMsg save it for later reply
* do some other stuff here RSN like the command line etc
nop
movem.l (sp)+,d0/a0 restore
end_startup
bsr.s _main call our program
* returns to here with exit code in d0
move.l d0,-(sp) save it
tst.l returnMsg
beq.s exitToDOS if I was a CLI
move.l 4.w,a6
jsr _LVOForbid(a6)
move.l returnMsg(pc),a1
jsr _LVOPermit(a6)
exitToDOS
move.l (sp)+,d0 exit code
rts
* startup code variable
returnMsg dc.l 0
* the program starts here
even
_main
---------------------------------------------------------
4. How do I tell if I'm running on an Amiga 1200/4000?
======================================================
Do *NOT* check library revision numbers, V39 OS can and does
run on standard & ECS chipset machines (This Amiga 3000
is currently running V39).
This code will check for AGA
move.w $dff07c,d0
cmp.b #$f8,d0
bne.s .notaga
; Do your funky AGA Stuff in here!
.notaga
5. Use Relocatable Code
=======================
If you write demos that run from a fixed address you should be shot.
NEVER EVER DO THIS. It's stupid and completely unnecessary.
If you require bitplanes to be on a 64Kb boundary then try the
following (in pseudo-code because I'm too lazy to write it in asm
for you):
for c=0 to (top of chip ram) step 65536
if AllocAbs(c,NUMBER_OF_BYTES_YOU_WANT) == TRUE then goto ok:
next c:
print "sorry. No free ram. Close down something and retry demo!"
stop
ok: Run_Outrageous_demo with mem at c
Keep your code in multiple sections. Several small sections are
better than one large section, they will more easilly fit in and run
on a system with fragmented memory.
6. Don't Crunch demos!
======================
Don't ever use Tetrapack or Bytekiller based packers. They are crap.
Many more demos fall over due to being packed with crap packers than
anything else. If you are spreading your demo by electronic means
(which most people do now, the days of the SAE Demodisks are long
gone!) then assemble your code, and use LHARC to archive it, you
will get better compression with LHARC than with most runtime
packers.
If you *have* to pack your demos, then use Powerpacker 4+, Turbo
Imploder or Titanics Cruncher, which I've had no problems with myself.
7. Don't use the K-Seka assembler!
==================================
It's dead and buried. Get a life, get a real assembler. Hisoft Devpac
is probably the best all-round assembler, although I use ArgAsm
which is astonishingly fast.
8. Don't use the hardware unless you have to!
=============================================
This one is aimed particularly at utility authors. I've seen some
*awfully* written utilities, for example (although I don't want
to single them out as there are plenty of others) the Kefrens
IFF converter.
There is NO REASON why this has to have it's own copperlist. A standard
OS-friendly version opening it's own screen works perfectly (I
still use the original SCA IFF-Converter), and multitasks properly.
9. Beware bogus input falling through to Workbench
==================================================
If you keep multitasking enabled and run your own copperlist remember
that any input (mouse clicks, key presses, etc) fall through to the
workbench. The correct way to get around this is to add an input
server to the IDCMP food chain (see - you *do* have to read the
other manuals!) at a high priority to grab all input events before
workbench/cli can get to them.
Look at the sourcecode for Protracker for an excellent example of
how to do the job properly. Well done Lars!
10. Have fun!
=============
Too many people out there (particularly the American OS-Lamic
Fundamentalists) try to tell us that you should never program at a hardware
level. If you're programming for fun, ignore them! But try and put
a little thought into how your code will work on other machines,
nothing annoys people more than downloading 400Kb of demo and then
finding it blows up on their machines. I'm not naming any names, but
there are quite a few groups who I have no intention of downloading
their demos again because I know it's a waste of download. With
the launch of the Amiga 1200 you cannot just write for 1.3 Amiga
500's any more. Let's go out there and write some shit hot demos!
11. Don't Publish Code you haven't checked!
===========================================
Thanks to Timo Rossi for spotting the stupid bug in my copper
setup routine (using LOFList instead of copinit). Funnily enough
my own setup routine uses the correct copinit code:
Please ignore the original file and use this instead.
12. Read this, it's new!
========================
A few points I've been asked to clear up:
Always use two copper end commands ie $FFFF,$FFFE,$FFFF,$FFFE.
Why? I'm not sure, but it definately said in the Harwdare
Ref book that you should, ISTR that some Amiga 1000's had a dodgy
copper that could overrun the first Copper End. If you look
at OS copperlists they all have (or at least did when I last looked!)
two END commands.
The 68010 and above processors have a Vector Base Register (VBR)
that allows the exception vector table to be placed anywhere in
RAM, including fast ram. This gives some speed benefits to systems
with this running, but at a cost.
Anything that accesses the interrupt locations directly, for example:
move.l $6c.w,old
move.l MyWickedInterruptCode,$6c.w
won't work... Unfortunately this includes 99.9% of demos.
I'm not going to tell you how to use the VBR to calculate
this, if you want to learn, get the excellent book 680x0 Programming
By Example, by Stan Kelly-Bootle (Howard Sams & Co). He gets paid
for telling you how to do this and I don't :-)
Plus that's not the best way to use interrupts on the Amiga. You
*should* use the Exec.Library function AddIntServer, but I know
most of you have a theological dislike of Library routines, only
opening the graphics.library to viciously poke it!
13 Using the blitter.
=====================
If you are using the blitter in your code and you are leaving the
system intact (as you should) always use the graphics.library
functions OwnBlitter() and DisownBlitter() to take control
of the blitter. Remember to free it for system use, many system
functions (including floppy disk data decoding) use the blitter.
Another big mistake I've seen is with blitter/processor timing.
Assuming that a particular routine will be slow enough that a blitter
wait is not needed is silly. Always check for blitter finished, and
wait if you need to.
Don't assume the blitter will always run at the same speed too. Think
about how your code would run if the processor or blitter were running
at 100 times the current speed. As long as you keep this in mind,
you'll be in a better frame of mind for writing compatable code.
14 NTSC
=======
As an European myself, I'm naturally biased agains the inferior video
system, but even though the US & Canada have a relatively minor Amiga
community compared with Europe (Sorry, it's true :-) we should still
help them out, even though they've never done a PAL Video Toaster for
us (sob!).
You have two options.
Firstly, you could write your code only to use the first 200 display
lines, and leave a black border at the bottom. This annoys PAL owners,
who rightly expect things to have a full display. It took long enough
for European games writers to work out that PAL displays were better.
You could write code that automatically checked which system it is
running on and ran the correct code accordingly:
(How to check: Note, this is probably not the officialy supported method,
but so many weird things happen with new monitors on AGA machines that
I prefer this method, it's simpler, and works under any Kickstart)
move.l 4.w,a6 ; execbase
cmp.b #50,PowerSupplyFrequency(a6) ; 531(a6)
beq.s .pal
jmp I'm NTSC (or more accurately, I'm running from 60Hz power)
.pal jmp I'm PAL (or I'm running from 50hz power).
If people have already switched modes to PAL, or if they are running
some weird software like the ICD Flicker Free Video Prefs thingy, then
this completely ignores them, but that serves them right for trying
to be clever :-)
Probably better would be to check VBlankFrequency(a6) [530(a6)]
as well, if both are 60Hz then it's definately a NTSC machine. If
one or more are 50Hz, then it's probably a better idea to run in PAL.
Now, if you want to force a machine into the other display system
you need some magic pokes: Here you go (beware other bits in
$dff1dc can do nasty things. One bit can reverese the polarity
on the video sync, not to healthy for some monitors I've heard...)
To turn a NTSC system into PAL (50Hz)
move.w #32,$dff1dc ; Magically PAL
To turn a PAL system into NTSC (60Hz)
move.w #0,$dff1dc ; Magically NTSC
Remember: Not all displays can handle both display systems!
Commdore 1084/1084S, Philips 8833/8852 and multisync monitors
will, and very few TV's will handle PAL signals (especially
if being used with a NTSC Amiga modulator). I gather that
most NTSC machines are Amiga 2000's, so perhaps this isn't
a problem.
So come on you NTSC users, tell us how you would prefer
the demos written!
Thanks to everyone who has replied. Any more questions, queries,
or "CJ, you got it wrong again!" type mail to the email
address below....
--------------------------------------------------------------------
This text is Copyright (C) 1992 Share and Enjoy, but may be freely
distributed in any electronic form.
All opinions expressed in this article are my own, and in no way
reflect those of Share and Enjoy or any BBS this file may be found
on.
I didn't write this for fun, I wrote it for you to use!
If you strongly disagree with anything I write, or you want to send me
some source or demos to test on Amiga 1200/4000 etc, or you have
questions about Amiga programming, or suggestions for future articles,
or just want to chat about the best way to optimise automatic copperlist
generation code, then contact me via email at:
comradej@althera.demon.co.uk or by email at Bad Dreams BBS.